package main

import (
	"bufio"
	"fmt"
	"io"
	"io/fs"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
)

func main() {
	if len(os.Args) < 4 {
		fmt.Println("Usage: go run create.go <target_dir> <module_name> <port>")
		fmt.Println("Example: go run create.go ../my-new-project github.com/myuser/my-project 8080")
		os.Exit(1)
	}

	targetDir := os.Args[1]
	newModuleName := os.Args[2]
	newPort := os.Args[3]

	// 验证端口格式
	if _, err := strconv.Atoi(newPort); err != nil {
		fmt.Printf("Error: Invalid port '%s', must be a number\n", newPort)
		os.Exit(1)
	}

	// 获取当前目录
	currentDir, err := os.Getwd()
	if err != nil {
		fmt.Printf("Error getting current directory: %v\n", err)
		os.Exit(1)
	}

	// 读取当前的模块名
	currentModuleName, err := getCurrentModuleName(filepath.Join(currentDir, "go.mod"))
	if err != nil {
		fmt.Printf("Error reading current module name: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("Creating new project from template...\n")
	fmt.Printf("Source: %s\n", currentDir)
	fmt.Printf("Target: %s\n", targetDir)
	fmt.Printf("Module: %s -> %s\n", currentModuleName, newModuleName)
	fmt.Printf("Port: 8200 -> %s\n", newPort)

	// 检查目标目录是否存在
	if _, err := os.Stat(targetDir); err == nil {
		fmt.Printf("Target directory '%s' already exists, removing it...\n", targetDir)
		
		// 尝试修复权限问题再删除
		if err := fixPermissionsAndRemove(targetDir); err != nil {
			fmt.Printf("Error removing existing directory: %v\n", err)
			fmt.Printf("Please manually remove the directory and try again:\n")
			fmt.Printf("chmod -R 755 %s && rm -rf %s\n", targetDir, targetDir)
			os.Exit(1)
		}
		fmt.Printf("Successfully removed existing directory\n")
	}

	// 创建目标目录
	fmt.Printf("Creating target directory...\n")
	if err := os.MkdirAll(targetDir, 0755); err != nil {
		fmt.Printf("Error creating target directory: %v\n", err)
		os.Exit(1)
	}

	// 复制文件并替换内容
	err = copyAndReplace(currentDir, targetDir, currentModuleName, newModuleName, newPort)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		os.Exit(1)
	}

	// 创建.env文件并配置端口
	err = createEnvFile(targetDir, newPort)
	if err != nil {
		fmt.Printf("Warning: Failed to create .env file: %v\n", err)
	} else {
		fmt.Printf("Created .env file with port %s\n", newPort)
	}

	fmt.Printf("Project created successfully at %s\n", targetDir)
	fmt.Printf("To start the new project:\n")
	fmt.Printf("  cd %s\n", targetDir)
	fmt.Printf("  go mod tidy\n")
	fmt.Printf("  go run cmd/server/main.go\n")
}

// 获取当前模块名
func getCurrentModuleName(goModPath string) (string, error) {
	file, err := os.Open(goModPath)
	if err != nil {
		return "", err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if strings.HasPrefix(line, "module ") {
			return strings.TrimSpace(strings.TrimPrefix(line, "module")), nil
		}
	}

	return "", fmt.Errorf("module declaration not found in go.mod")
}

// 复制文件并替换内容
func copyAndReplace(srcDir, destDir, oldModule, newModule, newPort string) error {
	return filepath.WalkDir(srcDir, func(path string, d fs.DirEntry, err error) error {
		if err != nil {
			return err
		}

		// 计算相对路径
		relPath, err := filepath.Rel(srcDir, path)
		if err != nil {
			return err
		}

		// 跳过排除的目录和文件
		if shouldSkip(relPath) {
			if d.IsDir() {
				return filepath.SkipDir
			}
			return nil
		}

		destPath := filepath.Join(destDir, relPath)

		if d.IsDir() {
			return os.MkdirAll(destPath, 0755)
		}

		// 复制并处理文件
		return copyFile(path, destPath, oldModule, newModule, newPort)
	})
}

// 判断是否应该跳过文件或目录
func shouldSkip(path string) bool {
	excludePaths := []string{
		".claude",
		".env",      // 排除实际的.env文件，但保留.env.example
		".git",
		".idea",
		"create.go", // 跳过脚手架程序源码
		"create",    // 跳过脚手架二进制文件
	}

	for _, exclude := range excludePaths {
		// 特殊处理.env文件：只排除.env，不排除.env.example等
		if exclude == ".env" {
			if filepath.Base(path) == ".env" {
				return true
			}
			continue
		}
		
		if strings.HasPrefix(path, exclude) || strings.Contains(path, string(filepath.Separator)+exclude) {
			return true
		}
		if filepath.Base(path) == exclude {
			return true
		}
	}

	return false
}

// 复制文件并替换内容
func copyFile(srcPath, destPath, oldModule, newModule, newPort string) error {
	src, err := os.Open(srcPath)
	if err != nil {
		return err
	}
	defer src.Close()

	// 创建目标文件的目录
	if err := os.MkdirAll(filepath.Dir(destPath), 0755); err != nil {
		return err
	}

	dest, err := os.Create(destPath)
	if err != nil {
		return err
	}
	defer dest.Close()

	// 如果是需要替换内容的文件类型，进行内容替换
	if shouldReplaceContent(srcPath) {
		return replaceContentAndWrite(src, dest, oldModule, newModule, newPort)
	}

	// 否则直接复制
	_, err = io.Copy(dest, src)
	return err
}

// 判断是否需要替换内容
func shouldReplaceContent(path string) bool {
	ext := strings.ToLower(filepath.Ext(path))
	filename := strings.ToLower(filepath.Base(path))

	replaceExts := []string{
		".go", ".mod", ".sum", ".md", ".json", ".yaml", ".yml", 
		".toml", ".txt", ".sql", ".http", ".env",
	}

	for _, replaceExt := range replaceExts {
		if ext == replaceExt {
			return true
		}
	}

	// 检查特殊文件名
	replaceFiles := []string{
		"makefile", "dockerfile", "readme", "license",
	}

	for _, replaceFile := range replaceFiles {
		if strings.Contains(filename, replaceFile) {
			return true
		}
	}

	return false
}

// 替换内容并写入
func replaceContentAndWrite(src io.Reader, dest io.Writer, oldModule, newModule, newPort string) error {
	scanner := bufio.NewScanner(src)
	writer := bufio.NewWriter(dest)
	defer writer.Flush()

	for scanner.Scan() {
		line := scanner.Text()
		
		// 替换模块名
		line = strings.ReplaceAll(line, oldModule, newModule)
		
		// 替换端口相关配置
		line = replacePortConfig(line, newPort)
		
		if _, err := writer.WriteString(line + "\n"); err != nil {
			return err
		}
	}

	return scanner.Err()
}

// 替换端口配置
func replacePortConfig(line, newPort string) string {
	// 替换配置文件中的默认端口 8200
	line = strings.ReplaceAll(line, `"8200"`, `"`+newPort+`"`)
	line = strings.ReplaceAll(line, `'8200'`, `'`+newPort+`'`)
	line = strings.ReplaceAll(line, `:8200`, `:`+newPort)
	
	// 替换 SERVER_PORT 环境变量的默认值
	re := regexp.MustCompile(`getEnv\("SERVER_PORT",\s*"8200"\)`)
	line = re.ReplaceAllString(line, `getEnv("SERVER_PORT", "`+newPort+`")`)
	
	// 替换 HTTP 客户端配置中的端口
	re2 := regexp.MustCompile(`http://localhost:8080`)
	line = re2.ReplaceAllString(line, `http://localhost:`+newPort)
	
	// 替换其他可能的端口引用
	re3 := regexp.MustCompile(`localhost:8080`)
	line = re3.ReplaceAllString(line, `localhost:`+newPort)
	
	return line
}

// 修复权限并删除目录
func fixPermissionsAndRemove(dir string) error {
	// 递归修复权限
	err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
		if err != nil {
			// 如果遇到权限错误，尝试修复当前目录权限
			if os.IsPermission(err) {
				if chmodErr := os.Chmod(filepath.Dir(path), 0755); chmodErr != nil {
					return chmodErr
				}
				// 重新尝试访问
				return nil
			}
			return err
		}
		
		// 修复当前路径的权限
		if d.IsDir() {
			return os.Chmod(path, 0755)
		}
		return os.Chmod(path, 0644)
	})
	
	if err != nil {
		// 如果walk失败，尝试直接修复根目录权限
		os.Chmod(dir, 0755)
	}
	
	// 删除目录
	return os.RemoveAll(dir)
}

// 创建.env文件并替换端口配置
func createEnvFile(targetDir, newPort string) error {
	envExamplePath := filepath.Join(targetDir, ".env.example")
	envPath := filepath.Join(targetDir, ".env")

	// 检查.env.example是否存在
	if _, err := os.Stat(envExamplePath); os.IsNotExist(err) {
		return fmt.Errorf(".env.example file not found in target directory")
	}

	// 读取.env.example文件
	content, err := os.ReadFile(envExamplePath)
	if err != nil {
		return fmt.Errorf("failed to read .env.example: %v", err)
	}

	// 替换端口配置
	contentStr := string(content)
	contentStr = strings.ReplaceAll(contentStr, "SERVER_PORT=8200", "SERVER_PORT="+newPort)

	// 写入.env文件
	err = os.WriteFile(envPath, []byte(contentStr), 0644)
	if err != nil {
		return fmt.Errorf("failed to write .env file: %v", err)
	}

	return nil
}